﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace SocialKit.LightRest
{
    /// <summary>
    /// Reprensents a collection of values used for a query string of a Uri.
    /// </summary>
    public sealed class HttpQueryString : Collection<KeyValuePair<string, string>>
    {
        /// <summary>
        /// Initialize a new instance of SocialKit.LightRest.HttpQueryString class.
        /// </summary>
        public HttpQueryString() { }

        /// <summary>
        /// Initialize a new instance of SocialKit.LightRest.HttpQueryString class.
        /// </summary>
        /// <param name="initialValues">Initial values.</param>
        public HttpQueryString(IEnumerable<KeyValuePair<string, string>> initialValues)
        {
            if (initialValues != null)
            {
                foreach (var p in initialValues)
                {
                    this.Add(p);
                }
            }
        }

        /// <summary>
        /// Add a name and value into this HttpQueryString.
        /// </summary>
        /// <param name="name">The name of a QueryString.</param>
        /// <param name="value">The value of a QueryString.</param>
        public void Add(string name, string value)
        {
            this.Add(new KeyValuePair<string, string>(name, value));
        }

        /// <summary>
        /// Append a name and value to this HttpQueryString then return this HttpQueryString.
        /// </summary>
        /// <param name="name">The name of a QueryString.</param>
        /// <param name="value">The value of a QueryString.</param>
        /// <returns>The current HttpQueryString.</returns>
        public HttpQueryString Append(string name, string value)
        {
            this.Add(name, value);

            return this;
        }

        /// <summary>
        /// Generate a Uri with the current HttpQueryString as its query string.
        /// </summary>
        /// <param name="uri">The base uri to build.</param>
        /// <returns>A Uri.</returns>
        public Uri MakeQueryString(Uri uri)
        {
            return MakeQueryString(uri, this);
        }

        /// <summary>
        /// Build a new Uri with specified base Uri and an HttpQueryString.
        /// </summary>
        /// <param name="uri">The base Uri to build with.</param>
        /// <param name="queryString">The query string.</param>
        /// <returns>A Uri.</returns>
        public static Uri MakeQueryString(Uri uri, HttpQueryString queryString)
        {
            return MakeQueryString(uri, (IEnumerable<KeyValuePair<string, string>>)queryString);
        }

        static readonly Uri a_fake_host = new Uri("http://a.fake.host");

        /// <summary>
        /// Build a new Uri with specified base Uri and a collection contains query values.
        /// </summary>
        /// <param name="uri">The base Uri to build with.</param>
        /// <param name="values">The query values collection.</param>
        /// <returns>A Uri.</returns>
        public static Uri MakeQueryString(Uri uri, IEnumerable<KeyValuePair<string, string>> values)
        {
            if (uri == null)
                throw new ArgumentNullException("uri");

            if (values == null || values.Count() == 0)
                return uri;

            Uri mixedUri;
            string hostAndOrPath;

            if (uri.IsAbsoluteUri)
            {
                mixedUri = uri;

                hostAndOrPath = RestUtility.NormalizeUriWithoutQuery(uri);
            }
            else
            {
                //So ugly~~~ to fix :(
                mixedUri = new Uri(a_fake_host, uri);

                //remove the "/" if the uri does not starts with "/"
                hostAndOrPath = mixedUri.AbsolutePath.StartsWith(uri.ToString().Substring(0, 1)) ? mixedUri.AbsolutePath : mixedUri.AbsolutePath.Substring(1);
            }

            var queryValues = RestUtility.ParseQueryString(mixedUri.Query).Concat(values);

            return new Uri(hostAndOrPath + "?" + queryValues.ToQueryString(), UriKind.RelativeOrAbsolute);
        }
    }
}